import { Injectable, Optional } from '@nestjs/common';
import { ClsService, CLS_REQ } from 'nestjs-cls';
import type { FastifyRequest } from 'fastify';

/**
 * HTTP 请求工具类
 * 
 * 提供两种使用方式：
 * 1. 静态方法：需要显式传递 request 参数（适合工具函数、测试）
 * 2. 实例方法：自动从 CLS 获取 request（适合 Service、Controller）
 * 
 * @example
 * ```ts
 * // 方式 1：静态方法（传统方式）
 * const ip = RequestUtil.getClientIp(request);
 * 
 * // 方式 2：实例方法（从 CLS 获取）
 * class SomeService {
 *   constructor(private readonly requestUtil: RequestUtil) {}
 *   
 *   someMethod() {
 *     const ip = this.requestUtil.getIp();  // 自动从 CLS 获取 request
 *   }
 * }
 * ```
 */
@Injectable()
export class RequestUtil {
  constructor(@Optional() private readonly cls?: ClsService) {}
  /**
   * 获取客户端真实 IP 地址
   * 
   * 优先从代理头获取，支持多级代理
   * 
   * @param request Fastify 请求对象
   * @returns 客户端 IP 地址
   * 
   * @example
   * ```ts
   * const ip = RequestUtil.getClientIp(request);
   * console.log(ip); // '192.168.1.100'
   * ```
   */
  static getClientIp(request: FastifyRequest): string {
    // 1. 尝试从 X-Forwarded-For 头获取（支持多级代理）
    const forwarded = request.headers['x-forwarded-for'];
    if (forwarded) {
      const ips = typeof forwarded === 'string' ? forwarded.split(',') : forwarded;
      // 返回第一个 IP（真实客户端 IP）
      return ips[0].trim();
    }

    // 2. 尝试从 X-Real-IP 头获取
    const realIp = request.headers['x-real-ip'];
    if (realIp && typeof realIp === 'string') {
      return realIp.trim();
    }

    // 3. 使用 Fastify 提供的 IP
    return request.ip || 'unknown';
  }

  /**
   * 获取客户端 User-Agent
   * 
   * @param request Fastify 请求对象
   * @returns User-Agent 字符串
   */
  static getUserAgent(request: FastifyRequest): string | undefined {
    return request.headers['user-agent'];
  }

  /**
   * 判断是否为内网 IP
   * 
   * @param ip IP 地址
   * @returns 是否为内网 IP
   */
  static isPrivateIp(ip: string): boolean {
    if (!ip || ip === 'unknown') return false;

    // 内网 IP 范围
    const privateRanges = [
      /^127\./,                    // 127.0.0.0/8 (localhost)
      /^10\./,                     // 10.0.0.0/8
      /^172\.(1[6-9]|2\d|3[01])\./, // 172.16.0.0/12
      /^192\.168\./,               // 192.168.0.0/16
      /^::1$/,                     // IPv6 localhost
      /^fc00:/,                    // IPv6 private
      /^fe80:/,                    // IPv6 link-local
    ];

    return privateRanges.some((range) => range.test(ip));
  }

  // ============================================
  // 实例方法（从 CLS 自动获取 request）
  // ============================================

  /**
   * 从 CLS 获取当前请求对象
   * 
   * @private
   * @returns Fastify Request 或 undefined
   */
  private getRequest(): FastifyRequest | undefined {
    if (!this.cls) return undefined;
    return this.cls.get(CLS_REQ);
  }

  /**
   * 获取客户端 IP（从 CLS）
   * 
   * @returns 客户端 IP 地址
   * @throws 如果 CLS 未启用或不在请求上下文中
   * 
   * @example
   * ```ts
   * class UserService {
   *   constructor(private readonly requestUtil: RequestUtil) {}
   *   
   *   async createUser() {
   *     const ip = this.requestUtil.getIp();  // 自动从 CLS 获取
   *   }
   * }
   * ```
   */
  getIp(): string {
    const request = this.getRequest();
    if (!request) {
      return 'unknown';
    }
    return RequestUtil.getClientIp(request);
  }

  /**
   * 获取 User-Agent（从 CLS）
   * 
   * @returns User-Agent 字符串
   */
  getUserAgent(): string | undefined {
    const request = this.getRequest();
    if (!request) return undefined;
    return RequestUtil.getUserAgent(request);
  }

  /**
   * 获取客户端信息（从 CLS）
   * 
   * @returns 客户端信息对象
   */
  getClientInfo(): {
    ip: string;
    userAgent?: string;
    isPrivate: boolean;
  } {
    const ip = this.getIp();
    return {
      ip,
      userAgent: this.getUserAgent(),
      isPrivate: RequestUtil.isPrivateIp(ip),
    };
  }
}

